﻿using System;
using System.Timers;

namespace Matrix.Common.Utility
{
    /// <summary>
    /// 扫描枪键盘输入检测类
    /// </summary>
    /// <remarks>Added by leo 2015-11-30</remarks>
    public class ScanningGunMonitor
    {
        #region 内部成员
        Timer _Timer = new Timer();//计时器
        DateTime _TickTime = DateTime.MinValue;//记录前一次按键周期的时间
        string _TempText = string.Empty;//控件文本副本
        object _Sender;//保存外部控件源，用于发送事件时传回
        #endregion

        #region 事件
        /// <summary>
        /// 输入超时委托
        /// </summary>
        /// <param name="Sender">来源</param>
        public delegate void InputTimeOut(object Sender);
        /// <summary>
        /// 输入超时事件委托对象
        /// </summary>
        public event InputTimeOut OnInputTimeOut;
        /// <summary>
        /// 发送输入超时事件
        /// </summary>
        private void SendInputTimeOutEvent()
        {
            if (OnInputTimeOut != null)
                OnInputTimeOut(_Sender);
        }
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public ScanningGunMonitor()
        {
            _Timer.Elapsed += Timer_Elapsed;//内置事件对象绑定触发事件方法
        }
        #endregion

        #region 属性

        #region 条码最小长度
        int _MiniLength = 10;
        /// <summary>
        /// 读取或设置条码最小长度值，当超过一个时钟周期后，如果条码文本不符合最小长度则被丢弃。
        /// </summary>
        public int MiniLength
        {
            get { return _MiniLength; }
            set { _MiniLength = value; }
        }
        #endregion

        #region 按键间隔超时限定值
        int _TimeOut = 100;
        /// <summary>
        /// 读取或设置按键间隔超时限定值
        /// </summary>
        public int TimeOut
        {
            get { return _TimeOut; }
            set { _TimeOut = value; }
        }
        #endregion

        #region 时钟周期
        int _ClockTick = 100;
        /// <summary>
        /// 读取或设置内置时钟周期
        /// </summary>
        public int ClockTick
        {
            get { return _ClockTick; }
            set { _ClockTick = value; }
        }
        #endregion

        #endregion

        #region 方法
        /// <summary>
        /// 当发生按键时检查条码文本是否超时(开启内置时钟)
        /// </summary>
        /// <param name="sender">发送控件</param>
        /// <param name="inputText">条码文本</param>
        /// <returns>有效按键标志</returns>
        public bool CheckKeyPress(object sender, string inputText)
        {
            int gap;
            _Sender = sender;
            var thisTime = DateTime.Now;
            gap = thisTime.Subtract(_TickTime).Milliseconds;
            if (_TickTime == DateTime.MinValue)//第一次
            {
                _TickTime = thisTime;//保存时间现场，用于下一周期判断依据
                _Timer.Interval = _ClockTick;
                _Timer.Enabled = true;//开启时钟
                SendInputTimeOutEvent();//发送输入超时事件
                return true;//保留当前输入字符
            }
            else
            {
                if (gap > _TimeOut)
                {
                    _TickTime = thisTime;//保存时间现场，用于下一周期判断依据
                    StopCheckGap();//停止检查输入间隔
                    _TempText = "";//清空本地文本
                    SendInputTimeOutEvent();//发送输入超时事件
                    return false; //通知取消当前输入
                }
            }
            _TickTime = thisTime;//保存时间现场，用于下一周期判断依据
            _TempText = inputText;//保存文本，提供时钟事件判断依据
            return true;//保留当前输入
        }
        /// <summary>
        /// 停止检测时间间隔，重置状态，停止内置时钟
        /// </summary>
        private void StopCheckGap()
        {
            _TickTime = DateTime.MinValue;
            _Timer.Enabled = false;
        }
        /// <summary>
        /// 时钟事件方法
        /// </summary>
        /// <param name="sender">发送者</param>
        /// <param name="e">事件对象</param>
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            var gap = e.SignalTime.Subtract(_TickTime).Milliseconds;
            if (gap > _TimeOut)
            {
                StopCheckGap();//停止检测,可能是扫描枪扫描结束，也可能是手工输入间隔
                if (_TempText.Length < _MiniLength)//进一步检查长度，如果较短，说明为手工输入
                {
                    _TempText = "";//清空本地文本
                    SendInputTimeOutEvent();//发送输入超时事件
                }
            }

        }
        #endregion
    }
}
